package tge

import (
	"net"
	"sync"
	"time"
	"errors"
)

type Conn interface {
	ReadMsg() ([]byte, error)
	WriteMsg(args ...[]byte) (int, error)

	// 输出普通数据或 base64 数据，用于适配 tcp 和 websocket
	WriteWithBase64([]byte, []byte) (int, error)

	LocalAddr() net.Addr
	RemoteAddr() net.Addr
	Close()

	SetReadDeadline(t time.Time)
}

type tcpConn struct {
	sync.Mutex
	conn 		net.Conn
	isClosed	bool
	parser		*MsgParser
}

func NewTcpConn(conn net.Conn, parser *MsgParser) *tcpConn {
	c := &tcpConn{}
	c.conn = conn
	c.isClosed = false
	c.parser = parser
	return c
}

func (conn *tcpConn) WriteMsg(args ...[]byte) (int, error) {
	conn.Lock()
	defer conn.Unlock()
	if !conn.isClosed {
		return conn.parser.Write(conn.conn, args...)
	}
	return 0, errors.New("conn is closed")
}
	
func (conn *tcpConn) WriteWithBase64(buf []byte, buf64 []byte) (int, error) {
	return conn.WriteMsg(buf)
}

func (conn *tcpConn) ReadMsg()([]byte, error) {
	return conn.parser.Read(conn.conn)
}

func (conn *tcpConn) LocalAddr() net.Addr {
	return conn.conn.LocalAddr()
}

func (conn *tcpConn) RemoteAddr() net.Addr {
	return conn.conn.RemoteAddr()
}

func (conn *tcpConn) Close() {
	conn.Lock()
	defer conn.Unlock()
	if !conn.isClosed {
		conn.conn.SetReadDeadline(time.Now().Add(10 * time.Second))
		conn.isClosed = true
	}
}

func (conn *tcpConn) SetReadDeadline(t time.Time) {
	conn.Lock()
	defer conn.Unlock()
	if !conn.isClosed {
		conn.conn.SetReadDeadline(t)
	}
}

type udpConn struct {
	sync.Mutex
	addr 		*net.UDPAddr
	srv 		*UdpServer
	r 			chan []byte
	isClosed	bool
}

func NewUdpConn(addr *net.UDPAddr, srv *UdpServer) *udpConn {
	c := &udpConn{}
	c.addr = addr
	c.srv = srv
	c.r = make(chan []byte, 10)
	c.isClosed = false
	return c
}

func (conn *udpConn) WriteMsg(args ...[]byte) (int, error) {
	conn.Lock()
	defer conn.Unlock()
	if !conn.isClosed {
		return conn.srv.SendTo(conn.addr, args...)
	}
	return 0, errors.New("conn is closed")
}
	
func (conn *udpConn) WriteWithBase64(buf []byte, buf64 []byte) (int, error) {
	return conn.WriteMsg(buf)
}

func (conn *udpConn) ReadMsg()([]byte, error) {
	return <-conn.r, nil
}

func (conn *udpConn) Read(msg []byte) {
	conn.Lock()
	defer conn.Unlock()
	if !conn.isClosed {
		conn.r <- msg
	}
}

func (conn *udpConn) LocalAddr() net.Addr {
	return conn.addr
}

func (conn *udpConn) RemoteAddr() net.Addr {
	return conn.addr
}

func (conn *udpConn) Close() {
	conn.Lock()
	defer conn.Unlock()
	if !conn.isClosed {
		conn.isClosed = true
	}
}

func (conn *udpConn) SetReadDeadline(t time.Time) {
}
